package com.jingfang.cloud.widget.show;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.json.JSONUtil;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.uiDesigner.core.Spacer;
import com.jingfang.cloud.MzContext;
import com.jingfang.cloud.MzPrefs;
import com.jingfang.cloud.core.model.ResultModel;
import com.jingfang.cloud.widget.main.MainWidget;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.plaf.FontUIResource;
import javax.swing.text.StyleContext;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

@Slf4j
@Getter
@Setter
public class ShowComponent {
    private final MainWidget owner;
    private final MzContext context;
    private final MzPrefs prefs;
    private final ResultModel resultModel;
    private final ShowDialog showDialog;
    private JPanel contentPanel;
    private JPanel fs1Panel;
    private JPanel fs2Panel;
    private JPanel fs3Panel;
    private JToggleButton fs1Btn;
    private JToggleButton fs2Btn;
    private JToggleButton fs3Btn;
    private JCheckBox ch1;
    private JCheckBox ch2;
    private JCheckBox ch3;
    private JCheckBox ch4;
    private JCheckBox ch5;
    private JCheckBox ch6;
    private JButton saveBtn;
    private JPanel loadingPanel;
    private JPanel controlPanel;
    private File file;

    public ShowComponent(MainWidget owner, ShowDialog showDialog, File file, ResultModel resultModel) {
        this.owner = owner;
        this.resultModel = resultModel;
        this.showDialog = showDialog;
        $$$setupUI$$$();
        this.context = (MzContext) owner.getContext();
        this.prefs = owner.getPrefs();
        this.file = file;
        this.initUI();
        this.initComponents();
        context.taskExecute(this::processDataFile, (data, ex) -> {
            if (ex != null) {
                owner.displayException(ex);
                return;
            }
            this.loadingPanel.setVisible(false);
            this.controlPanel.setVisible(true);
            for (Map.Entry<Integer, ChartPanel> panelEntry : data.entrySet()) {
                if (panelEntry.getKey() == 1) {
                    fs1Panel.add(panelEntry.getValue(), BorderLayout.CENTER);
                } else if (panelEntry.getKey() == 2) {
                    fs2Panel.add(panelEntry.getValue(), BorderLayout.CENTER);
                } else {
                    fs3Panel.add(panelEntry.getValue(), BorderLayout.CENTER);
                }
            }
        });
    }

    private void initComponents() {
        fs1Btn.addActionListener(e -> {
            fs1Panel.setVisible(true);
            fs2Panel.setVisible(false);
            fs3Panel.setVisible(false);

            fs1Btn.setSelected(true);
            fs2Btn.setSelected(false);
            fs3Btn.setSelected(false);
        });
        fs2Btn.addActionListener(e -> {
            fs1Panel.setVisible(false);
            fs2Panel.setVisible(true);
            fs3Panel.setVisible(false);

            fs1Btn.setSelected(false);
            fs2Btn.setSelected(true);
            fs3Btn.setSelected(false);
        });
        fs3Btn.addActionListener(e -> {
            fs1Panel.setVisible(false);
            fs2Panel.setVisible(false);
            fs3Panel.setVisible(true);
            fs1Btn.setSelected(false);
            fs2Btn.setSelected(false);
            fs3Btn.setSelected(true);
        });
        saveBtn.addActionListener(e -> {
            String[] ret = new String[6];
            if (ch1.isSelected()) {
                ret[0] = ch1.getText();
            }
            if (ch2.isSelected()) {
                ret[1] = ch2.getText();
            }
            if (ch3.isSelected()) {
                ret[2] = ch3.getText();
            }
            if (ch4.isSelected()) {
                ret[3] = ch4.getText();
            }
            if (ch5.isSelected()) {
                ret[4] = ch5.getText();
            }
            if (ch6.isSelected()) {
                ret[5] = ch6.getText();
            }
            resultModel.setNotes(ret);
            String summaryFile = file.getParent() + File.separator + "summary.json";
            FileUtil.writeString(JSONUtil.toJsonPrettyStr(resultModel), summaryFile, "UTF-8");
            ZipUtil.zip(file.getParent(), file.getParent() + ".zip");
            FileUtil.del(file.getParent());
            owner.displayMessage("成功", "数据标记保存成功！");
            showDialog.setVisible(false);
            showDialog.dispose();
        });
    }

    private void initUI() {
        fs1Btn.setSelected(true);
        fs1Btn.setFocusable(false);
        fs2Btn.setFocusable(false);
        fs3Btn.setFocusable(false);
        fs1Panel.setVisible(true);
        fs2Panel.setVisible(false);
        fs3Panel.setVisible(false);
    }

    private Map<Integer, ChartPanel> processDataFile() throws IOException {
        int rows = 1;
        int cols = 258;
        int packetLen = rows * cols;
        Map<Integer, ChartPanel> panels = new HashMap<>();
        try (DataInputStream dis = new DataInputStream(Files.newInputStream(file.toPath()))) {
            ArrayList<int[]> sensorData = new ArrayList<>();
            while (dis.available() >= packetLen) {
                byte[] packet = new byte[packetLen];
                dis.readFully(packet);

                // 校验和计算
                int checksumCalc = 0;
                for (int j = 0; j < cols - 2; j++) {
                    checksumCalc += Byte.toUnsignedInt(packet[j]);
                }
                checksumCalc &= 0xFFFF;
                int checksumRecv = Byte.toUnsignedInt(packet[cols - 2]) +
                        (Byte.toUnsignedInt(packet[cols - 1]) << 8);

                if (checksumCalc == checksumRecv) {
                    int[] data = new int[108];
                    for (int j = 0; j < 108; j++) {
                        data[j] = Byte.toUnsignedInt(packet[40 + 2 * j]) +
                                (Byte.toUnsignedInt(packet[41 + 2 * j]) << 8);
                    }
                    sensorData.add(data);
                } else {
                    log.error("checksum: calc = {}; recv = {}; error\n", checksumCalc, checksumRecv);
                }
            }

            for (int i = 0; i < 3; i++) {
                int no = i + 1;
                XYSeries seriesSensor = new XYSeries(String.format("FS%d", no));
                for (int j = 0; j < sensorData.size(); j++) {
                    for (int k = 0; k < 18; k++) {
                        seriesSensor.add(j * 18 + k, sensorData.get(j)[i * 18 + k] / 100.0);
                    }
                }
                XYSeriesCollection datasetSensor = new XYSeriesCollection(seriesSensor);
                JFreeChart chartSensor = ChartFactory.createXYLineChart(
                        String.format("FS%d", no),
                        "",
                        "",
                        datasetSensor,
                        PlotOrientation.VERTICAL,
                        false,
                        true,
                        false
                );
                String fsImageFile = file.getParent() + File.separator + "通道%s.png";
                BufferedImage bufferedImage = chartSensor.createBufferedImage(1600, 1200);
                ImageIO.write(bufferedImage, "png", new File(String.format(fsImageFile, no)));
                ChartPanel chartPanel = new ChartPanel(chartSensor);
                chartPanel.setPreferredSize(new Dimension(800, 600));
                panels.put(no, chartPanel);
            }
        }
        return panels;
    }


    /**
     * Method generated by IntelliJ IDEA GUI Designer
     * >>> IMPORTANT!! <<<
     * DO NOT edit this method OR call it in your code!
     *
     * @noinspection ALL
     */
    private void $$$setupUI$$$() {
        createUIComponents();
        contentPanel = new JPanel();
        contentPanel.setLayout(new GridLayoutManager(5, 3, new Insets(0, 0, 0, 0), -1, -1));
        fs1Panel = new JPanel();
        fs1Panel.setLayout(new BorderLayout(0, 0));
        contentPanel.add(fs1Panel, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        fs2Panel = new JPanel();
        fs2Panel.setLayout(new BorderLayout(0, 0));
        contentPanel.add(fs2Panel, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        fs3Panel = new JPanel();
        fs3Panel.setLayout(new BorderLayout(0, 0));
        contentPanel.add(fs3Panel, new GridConstraints(1, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        controlPanel = new JPanel();
        controlPanel.setLayout(new GridLayoutManager(3, 6, new Insets(10, 0, 30, 0), -1, -1));
        controlPanel.setEnabled(true);
        controlPanel.setVisible(false);
        contentPanel.add(controlPanel, new GridConstraints(3, 0, 1, 3, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        final Spacer spacer1 = new Spacer();
        controlPanel.add(spacer1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
        final Spacer spacer2 = new Spacer();
        controlPanel.add(spacer2, new GridConstraints(0, 5, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
        final JPanel panel1 = new JPanel();
        panel1.setLayout(new GridLayoutManager(2, 3, new Insets(0, 0, 0, 0), -1, -1));
        controlPanel.add(panel1, new GridConstraints(1, 1, 1, 4, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        ch1 = new JCheckBox();
        ch1.setText("沉脉");
        panel1.add(ch1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        ch2 = new JCheckBox();
        ch2.setText("浮脉");
        panel1.add(ch2, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        ch3 = new JCheckBox();
        ch3.setText("迟脉");
        panel1.add(ch3, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        ch4 = new JCheckBox();
        ch4.setText("数脉");
        panel1.add(ch4, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        ch5 = new JCheckBox();
        ch5.setSelected(false);
        ch5.setText("虚脉");
        panel1.add(ch5, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        ch6 = new JCheckBox();
        ch6.setText("实脉");
        panel1.add(ch6, new GridConstraints(1, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JPanel panel2 = new JPanel();
        panel2.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1));
        controlPanel.add(panel2, new GridConstraints(2, 1, 1, 4, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        saveBtn = new JButton();
        saveBtn.setText("记录脉象");
        panel2.add(saveBtn, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        controlPanel.add(fs1Btn, new GridConstraints(0, 1, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        controlPanel.add(fs2Btn, new GridConstraints(0, 3, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        controlPanel.add(fs3Btn, new GridConstraints(0, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        final Spacer spacer3 = new Spacer();
        contentPanel.add(spacer3, new GridConstraints(4, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
        final JSeparator separator1 = new JSeparator();
        contentPanel.add(separator1, new GridConstraints(2, 0, 1, 3, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
        loadingPanel = new JPanel();
        loadingPanel.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1));
        contentPanel.add(loadingPanel, new GridConstraints(0, 0, 1, 3, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        final JLabel label1 = new JLabel();
        Font label1Font = this.$$$getFont$$$(null, -1, 22, label1.getFont());
        if (label1Font != null) label1.setFont(label1Font);
        label1.setText("图表数据生成中，请稍后...");
        loadingPanel.add(label1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
    }

    /**
     * @noinspection ALL
     */
    private Font $$$getFont$$$(String fontName, int style, int size, Font currentFont) {
        if (currentFont == null) return null;
        String resultName;
        if (fontName == null) {
            resultName = currentFont.getName();
        } else {
            Font testFont = new Font(fontName, Font.PLAIN, 10);
            if (testFont.canDisplay('a') && testFont.canDisplay('1')) {
                resultName = fontName;
            } else {
                resultName = currentFont.getName();
            }
        }
        Font font = new Font(resultName, style >= 0 ? style : currentFont.getStyle(), size >= 0 ? size : currentFont.getSize());
        boolean isMac = System.getProperty("os.name", "").toLowerCase(Locale.ENGLISH).startsWith("mac");
        Font fontWithFallback = isMac ? new Font(font.getFamily(), font.getStyle(), font.getSize()) : new StyleContext().getFont(font.getFamily(), font.getStyle(), font.getSize());
        return fontWithFallback instanceof FontUIResource ? fontWithFallback : new FontUIResource(fontWithFallback);
    }

    /**
     * @noinspection ALL
     */
    public JComponent $$$getRootComponent$$$() {
        return contentPanel;
    }

    private void createUIComponents() {
        fs1Btn = new JToggleButton("FS1");
        fs2Btn = new JToggleButton("FS2");
        fs3Btn = new JToggleButton("FS3");
    }
}
